import fs from 'fs';
import { pre_proc } from './pre_proc';
import { filter } from './filter';
import { Obj, Reg, Comb, Obuf, Ibuf, M9k, Mout, Mul, } from './defs';

export const proc = (file: string, exclude: string[]) => {
  var data = fs.readFileSync(file);
  //var data = fs.readFileSync("E:/MyCodeV2/fpga/USB3/blink/simulation/custom/blink.vo");

  var assign: { [key: string]: string } = {};
  var objs: Obj[] = [];

  pre_proc(data, assign, objs);


  var allRegs: Reg[] = [];
  var combs: Comb[] = [];
  var obufs: Obuf[] = [];
  var ibufs: Ibuf[] = [];
  var m9ks: M9k[] = [];
  var mouts: Mout[] = [];
  var muls: Mul[] = [];
  var outMap: { [key: string]: Obj } = {};
  filter(
    objs,

    allRegs,
    combs,
    obufs,
    ibufs,
    m9ks,
    mouts,
    muls,
    outMap,
  );


  var fixed: any = {
    "gnd": true,
    "vcc": true,
    "\\ddr2_phy_alt_mem_phy_inst|clk|pll|altpll_component|auto_generated|pll1~LOCKED": true,
    '\\ddr2_phy_alt_mem_phy_inst|clk|pll|altpll_component|auto_generated|pll1~PHASEDONE': true,
    '\\cpu_pll_inst|altpll_component|auto_generated|wire_pll1_clk[0]~clkctrl_outclk': true,
  };
  var proc = (inv: string) => {
    var ret = undefined;
    if (fixed[inv]) {
      return ret;
    }
    if (inv.startsWith("!")) {
      inv = inv.substring(1);
    }
    if (inv.startsWith("\\altera_internal_jtag")) {
      return ret;
    }
    if (assign[inv]) {
      inv = assign[inv];
      inv = inv.split(" ")[0];
    }
    if (inv) {
      if (outMap[inv]) {
        ret = outMap[inv];
      } else {
        console.log(inv);
      }
    }
    return ret;
  };

  var clocks: { [keys: string]: { regs: Reg[], paths: string[][] } } = {};
  allRegs.forEach((reg) => {
    reg._in = proc(reg.in);
    reg._ena = proc(reg.ena);
    reg._sload = proc(reg.sload);
    reg._sclr = proc(reg.sclr);
    reg._asdata = proc(reg.asdata);
    var clock = clocks[reg.clk];
    if (!clock) {
      clock = { regs: [], paths: [] };
      clocks[reg.clk] = clock;
    }
    clock.regs.push(reg);
  });

  combs.forEach((comb) => {
    comb._in1 = proc(comb.in1);
    comb._in2 = proc(comb.in2);
    comb._in3 = proc(comb.in3);
    comb._in4 = proc(comb.in4);
    comb._inc = proc(comb.inc);
  });

  // obufs.forEach((obuf) => {
  //   obuf._in = proc(obuf.in);
  //   obuf._oe = proc(obuf.oe);
  // });

  var clockList = Object.keys(clocks).sort((a, b) => { return a.localeCompare(b); });
  
  console.log(clockList);

  clockList.forEach((key) => {
    console.log("digin:" + key);
    var regs = clocks[key].regs;
    var paths = clocks[key].paths;
    var digin = (obj: Obj | undefined, path: Obj[]) => {
      if (obj) {
        if (obj.type == "cycloneive_lcell_comb") {
          if (obj.name != "\\system_inst|ro_b|notgate_in" && obj.name != "\\system_inst|ro_a|notgate_in") {
            var comb = obj as Comb;
            digin(comb._in1, [...path, obj]);
            digin(comb._in2, [...path, obj]);
            digin(comb._in3, [...path, obj]);
            digin(comb._in4, [...path, obj]);
            //digin(comb._inc, [...path, obj]);
          }
        }
        else {
          path.push(obj);
          var spath: string[] = [];
          path.forEach((obj) => {
            spath.push(obj.name);
          });
          paths.push(spath);
        }
      }
    };

    regs.forEach((reg) => {
      var found = false;
      exclude.forEach((e) => {
        if (reg.name.indexOf(e) >= 0) {
          found = true;
        }
      });
      if (found) {

      } else {
        digin(reg._in, [reg]);
        digin(reg._ena, [reg]);
        digin(reg._sload, [reg]);
        digin(reg._sclr, [reg]);
        digin(reg._asdata, [reg]);
      }
    });

    console.log("sort");

    paths.sort((a, b) => { return b.length - a.length; });

    for (var i = 0; i < 5; i++) {
      console.log(paths[i]);
    }



  });
};

// fs.writeFileSync("out.txt", outtext.join("\r\n"));
